package com.risen.project.controller;

import com.risen.project.common.ConstraintViolationTemplate;
import com.risen.project.common.ExceptionCore;
import com.risen.project.common.Response;
import com.risen.project.common.ResponseStatusCode;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 处理统一异常
 */
@RestControllerAdvice
public class ExceptionHandlerController {

    /**
     * 参数校验捕获器，捕获Validated抛出的异常
     *
     * @param e 异常信息
     * @return 返回信息
     */
    @ExceptionHandler(ValidationException.class)
    public Response<Void> validationException(ValidationException e) {

        if (e instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) e)
                    .getConstraintViolations();
            List<ConstraintViolationTemplate> constraintViolationTemplateList = new ArrayList<>();
            constraintViolations.forEach(f -> {
                ConstraintViolationTemplate constraintViolationTemplate = new ConstraintViolationTemplate();
                String[] attribute = f.getPropertyPath().toString().split("\\.", 2);
                constraintViolationTemplate.setParam(attribute[1]);
                constraintViolationTemplate.setMessage(f.getMessage());
                constraintViolationTemplateList.add(constraintViolationTemplate);
            });
            return Response.fail(ResponseStatusCode.PARAMETER_VALIDATE_IS_FAIL.getCode(), constraintViolationTemplateList.get(0).getMessage());
        }
        return null;
    }

    /**
     * 参数校验捕获器，捕获get请求的Valid注解抛出的异常
     *
     * @param e 异常信息
     * @return 返回信息
     */
    @ExceptionHandler(BindException.class)
    public Response<Void> bindException(BindException e) {
        List<ConstraintViolationTemplate> constraintViolationTemplateList = new ArrayList<>();
        e.getFieldErrors().forEach(f -> {
            ConstraintViolationTemplate constraintViolationTemplate = new ConstraintViolationTemplate();
            constraintViolationTemplate.setParam(f.getField());
            constraintViolationTemplate.setMessage(f.getDefaultMessage());
            constraintViolationTemplateList.add(constraintViolationTemplate);
        });
        return Response.fail(ResponseStatusCode.PARAMETER_VALIDATE_IS_FAIL.getCode(), constraintViolationTemplateList.get(0).getMessage());
    }

    /**
     * 参数有校验捕获器，捕获post请求的Valid注解抛出的异常
     *
     * @param e 异常信息
     * @return 返回信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Response<Void> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        List<ConstraintViolationTemplate> constraintViolationTemplateList = new ArrayList<>();
        e.getBindingResult().getFieldErrors().forEach(f -> {
            ConstraintViolationTemplate constraintViolationTemplate = new ConstraintViolationTemplate();
            constraintViolationTemplate.setParam(f.getField());
            constraintViolationTemplate.setMessage(f.getDefaultMessage());
            constraintViolationTemplateList.add(constraintViolationTemplate);
        });
        return Response.fail(ResponseStatusCode.PARAMETER_VALIDATE_IS_FAIL.getCode(), constraintViolationTemplateList.get(0).getMessage());
    }

    /**
     * 自定义异常拦截器
     *
     * @param e 自定义异常信息
     * @return 返回信息
     */
    @ExceptionHandler(ExceptionCore.class)
    public Response<Void> exceptionCore(ExceptionCore e) {
        ResponseStatusCode responseStatusCode = e.getResponseStatusCode();
        e.printStackTrace();
        return ObjectUtils.isEmpty(responseStatusCode) ? Response.fail("9998", e.getMessage()) : Response.fail(e.getResponseStatusCode());
    }

    /**
     * 这是@requestParam 拦截器 加了该注解 但是没有传参的话 会报异常
     *
     * @param e 异常信息
     * @return 返回信息
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Response<Void> missingRequestValueException(MissingServletRequestParameterException e) {
        return Response.fail(ResponseStatusCode.PARAMETER_VALIDATE_IS_FAIL.getCode(), e.getParameterName() + "不能为空");
    }

    /**
     * 请求方式拦截器 如果发生不支持请求方式 则会返回提示信息
     *
     * @param e 异常信息
     * @return 返回信息
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Response<Void> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        return Response.fail(ResponseStatusCode.HTTP_REQUEST_METHOD_NOT_SUPPORTED.getCode(), "请使用" + Arrays.toString(e.getSupportedMethods()) + "方式进行请求");
    }
}
